// *** LICENSE HEADER ***
// Filename: ./lightmanager.cpp
// This file is part of Nodewarz 0.1
// Nodewarz is a 3d OpenGL strategy game
// Copyright (C) 2007 CZestmyr
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// *** END LICENSE HEADER ***
#include "lightmanager.h"

lightManager::lightManager() {
    lightList = 0;
}

lightManager::~lightManager() {
    FlushLights();
}

void lightManager::SetGameBoardPointer(gameBoard* newBoard) {
    theBoard = newBoard;
}

light* lightManager::AddLight(float r, float g, float b, float x, float y, float radius) {
    //Create the light
    lightNode* nue = new lightNode;
    nue->data = new light(r, g, b, x, y, radius);
    nue->next = lightList;
    lightList = nue;
    //Recalculate the lightmap, if the gameboard is set
    if (theBoard)
        theBoard->RecalculateLighting(x, y, radius);
    //Return the new light pointer
    return nue->data;
}

void lightManager::RemoveLight(light* l) {
    lightNode* it = lightList;
    lightNode* prev;
    float x, y, radius;
    while (it) {
        if (it->data == l) {
            radius = it->data->GetRadius();
            x = it->data->GetX();
            y = it->data->GetY();
            if (it == lightList)
                lightList = it->next;
            else
                prev->next = it->next;
            delete it->data;
            delete it;
            if (theBoard)
                theBoard->RecalculateLighting(x, y, radius);
            return;
        }
        prev = it;
        it = it->next;
    }
}

void lightManager::RemoveLight(float x, float y) {
    lightNode* it = lightList;
    lightNode* prev;
    float radius;
    while (it) {
        if (it->data->GetX() == x && it->data->GetY() == y) {
            radius = it->data->GetRadius();
            if (it == lightList)
                lightList = it->next;
            else
                prev->next = it->next;
            delete it->data;
            delete it;
            if (theBoard)
                theBoard->RecalculateLighting(x, y, radius);
            return;
        }
        prev = it;
        it = it->next;
    }
}

void lightManager::FlushLights() {
    lightNode* it = lightList;
    lightNode* del;
    while (it) {
        del = it;
        it = it->next;
        delete del->data;
        delete del;
    }
    lightList = 0;
}

void lightManager::UpdateLightRadius(light* l, float newRadius) {
    float affectedArea = (l->GetRadius() > newRadius) ?
                         l->GetRadius() : newRadius;
    l->SetRadius(newRadius);
    if (theBoard)
        theBoard->RecalculateLighting(l->GetX(), l->GetY(), affectedArea);
}

void lightManager::GetLightColorAt(float x, float y, float& r, float& g, float& b) {
    lightNode* it = lightList;
    light* l;
    float dist;
    //Set the initial light color to black
    r = g = b = 0.0f;

    //Iterate through all the lights
    while (it) {
        l = it->data;
        dist = Distancef(l->GetX(), l->GetY(), x, y);
        //If the light is close to us enough, add its light to the light color
        if (dist < l->GetRadius()) {
            r += l->GetR() * (1.0f - dist / l->GetRadius());
            g += l->GetG() * (1.0f - dist / l->GetRadius());
            b += l->GetB() * (1.0f - dist / l->GetRadius());
        }
        it = it->next;
    }
}
